package com.pavlinic.codegen.dsl;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.Expression;
import org.eclipse.jdt.core.dom.MethodInvocation;
import org.mockito.cglib.proxy.MethodInterceptor;
import org.mockito.cglib.proxy.MethodProxy;
import org.mockito.internal.creation.jmock.ClassImposterizer;

public class MethodInvocationGenerator {
  private final Expression expression;
  private MethodInvocation methodInvocation;
  private final List<Expression> parameters = new ArrayList<Expression>();

  public MethodInvocationGenerator(Expression expression) {
    this.expression = expression;
  }
  
  @SuppressWarnings("unchecked")
  private MethodInvocation createMethodInvocation(Method method, Object[] arguments) {
    final AST ast = expression.getAST();
    final MethodInvocation newMethodInvocation = ast.newMethodInvocation();
    newMethodInvocation.setName(ast.newSimpleName(method.getName()));
    newMethodInvocation.setExpression(expression);
    for (Expression parameter : parameters) {
      newMethodInvocation.arguments().add(parameter);
    }
    return newMethodInvocation;
  }

  @SuppressWarnings("unchecked")
  public <T> T callMethod(Class<T> expressionType) {
    final MethodInterceptor interceptor = new MethodInterceptor() {
      @Override
      public Object intercept(Object obj, Method method, Object[] args,
          MethodProxy proxy) throws Throwable {
        methodInvocation = createMethodInvocation(method, args);
        return null;
      }
    };
    return (T) ClassImposterizer.INSTANCE.imposterise(interceptor, (Class<?>) expressionType, new Class<?>[0]);
  }

  public MethodInvocation getMethodInvocation() {
    return methodInvocation;
  }

  public long literalLong(long l) {
    parameters.add(expression.getAST().newNumberLiteral("" + l));
    return l;
  }

  public <T> T identifier(String identifierName, Class<T> clazz) {
    parameters.add(expression.getAST().newSimpleName(identifierName));
    return null;
  }
}
